package com.example.bootdemo.common.web;

import cn.hutool.json.JSONUtil;
import com.example.bootdemo.common.enums.ResultCodeEnum;
import com.example.bootdemo.common.exception.BusinessException;
import com.example.bootdemo.common.exception.ParameterException;
import com.example.bootdemo.common.vo.ResultInfoVO;
import com.example.bootdemo.utils.ResultInfoVOUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResultInfoVO handlerException(Exception ex) {
        log.error("未知异常", ex);

        return ResultInfoVOUtil.buildError(ex.getMessage());
    }

    /**
     * @author 公众号:干货食堂
     * @date 2021/10/2 20:11
     * 参数 ex
     * @return com.ganhuoshitang.kong.common.result.ResultInfoVO
     * @description: SQLException
     */
    @ExceptionHandler(SQLException.class)
    public ResultInfoVO SQLException(SQLException ex) {
        log.error("SQL执行异常 SQLException", ex);
        return ResultInfoVOUtil.buildError(ResultCodeEnum.SQL_EXCEPTION);
    }

    /**
     * 404 异常
     * @param ex
     * @return
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResultInfoVO noHandlerFoundException(NoHandlerFoundException ex) {
        log.error("404异常 NoHandlerFoundException");
        return ResultInfoVOUtil.buildError(ResultCodeEnum.NOTFOUND404);
    }

    /**
     * 参数异常
     * @param ex
     * @return
     */
    @ExceptionHandler(ParameterException.class)
    public ResultInfoVO handlerParameterException(ParameterException ex) {
        ResultCodeEnum resultCodeEnum = ex.getResultCodeEnum();
        log.error("业务参数校验异常 handlerParameterException", ex);
        return ResultInfoVOUtil.buildError(resultCodeEnum);
    }

    /**
     * 业务异常
     * @param ex
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public ResultInfoVO businessException(BusinessException ex) {
        ResultCodeEnum resultCodeEnum = ex.getResultCodeEnum();
        log.error("业务异常 businessException", ex);
        return ResultInfoVOUtil.buildError(resultCodeEnum);
    }

    /**
     * Controller层入参参数校验异常 ValidationException
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultInfoVO methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("入参校验异常 ValidationException", ex);
        BindingResult bindingResult = ex.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        Map<String, String> errorMap = new HashMap<>();
        for(FieldError error : fieldErrors){
            String field = error.getField();
            String defaultMessage = error.getDefaultMessage();
            errorMap.put(field,defaultMessage);
        }
        return ResultInfoVOUtil.buildError(JSONUtil.toJsonStr(errorMap));
    }


}